package sim;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;




public class Blob
{
	//If a blob's preference vector is not bigger than this, it does not need to move.
	private static final double I_CARE = 1;
	
	public static final double minBlobSize = 100;
	public static final double minBlobRadius = Math.sqrt(minBlobSize/Math.PI);
	private static final double baseSpeed = 100;
	private static final double speedBuffer = 100;

	private final double strength = .1;
	private final double growthRate = 70;
	private double metabolismConstant = .3; //How much energy/area/mass is left over after the rest of the area/mass is used to maintain the blob's metabolism
	private boolean processed;
    private Vec2 position;
	private double speed;
    private double area;
    private double radius;
    private AI ai;
	private Vec2 preferenceVector = new Vec2(0,0);
    
    public Blob(Vec2 position, double area, AI ai) 
    {
    	processed = false;
		setPosition(position);
		setArea(area);
		setAi(ai);
	}

	public void draw(Graphics2D g2d)
    {
		int blue = getBlue();
		int red = 255-blue;
        g2d.setColor(new Color(red,0,blue));
        TorusMath.instance.drawCircle(g2d, position.x, position.y, radius);
        
//        g2d.fillOval((int)(getPosition().GetX()-radius), (int)(getPosition().GetY()-radius), (int)(2*radius), (int)(2*radius));
    }
	private int getBlue() 
	{
		double reproductionArea = ai.getReproductionArea();
		if(reproductionArea <=0)
		{
			return 0;
		}
		else if(reproductionArea >=4000)
		{
			return 255;
		}		
		else
		{
			return (int)(255*reproductionArea/4000);
		}
	}

    public boolean haveCollided(Blob otherBlob)
    {
        
        if(Vec2.Distance(getPosition(),otherBlob.getPosition())<radius+otherBlob.radius)
        {
            return true;
        }
        
        return false;
    }
//    public void collisionWall(Vec2 upperLeft,Vec2 lowerRight)
//    {
//        if((getPosition().x-radius) <upperLeft.x)
//        {
//        	setPosition(new Vec2(upperLeft.x+radius, getPosition().y));
//        }
//        if((getPosition().y-radius) <upperLeft.y)
//        {
//        	setPosition(new Vec2(getPosition().x, upperLeft.y+radius));
//        }
//        if((getPosition().y+radius) >lowerRight.y)
//        {
//        	setPosition(new Vec2(getPosition().x, lowerRight.y-radius));
//        }
//        if((getPosition().x+radius)>lowerRight.x)
//        {
//        	setPosition(new Vec2(lowerRight.x-radius, getPosition().y));
//        }        
//    }
    public void separateBlobs(Blob otherBlob) //to be completed
    {
        //Normalized vector facing in from otherBlob to this blob
        Vec2 otherBlobRelativePositionNormalized = (getPosition().Sub(otherBlob.getPosition())).Unit();
  
    }
    /**
     * fight changes the areas of the blobs so both take damage, or returns the dead blob so it can be 
     * removed by World without damaging the other blob.
     * @param otherBlob
     * @return
     */
	public Blob fight(Blob otherBlob)
	{
		double tempArea = area;
		if (area - (otherBlob.getArea() * otherBlob.getStrength()) < minBlobSize)
		{
			otherBlob.changeArea(area*metabolismConstant); //get eaten by the other blob
			return this;
		}
		if (otherBlob.getArea() - (area * getStrength()) < minBlobSize)
		{
			changeArea(area*metabolismConstant); //eat the other blob
			return otherBlob;
		}
		else
		{
			changeArea(-otherBlob.getArea() * otherBlob.getStrength());
			otherBlob.changeArea(-tempArea * getStrength());
			return null;
		}
		
	}
	public boolean isEating (Food food)
	{
		double distance = TorusMath.instance.distance(position, radius, food.getPosition(), food.getRadius());
		return  distance < 0;
        //return (Vec2.Distance(position,food.getPosition())<radius+food.getRadius());
	}
	public void eat(Food food)
	//This should stop the blob from moving while it eats, call the decreaseArea method on the food as the blob takes bites
	//and increase the blob's energy.For now, I'm having it increase the blob's size instead.
	{
		double biteSize = 5;
       	food.decreaseArea(biteSize); //Keep bites small so it won't matter if a blob is the last one in the set to take a bite.
       	changeArea(biteSize*metabolismConstant);
       	//increaseEnergy(10);
    }
    
	public Blob compareBlobAreas(Blob otherBlob)
	{
		if (otherBlob.getArea()<this.getArea())
	return otherBlob;
		else
		{
			return this;
		}
	}	
    public void changeArea(double deltaArea)
    {
    	setArea(area+deltaArea);
    }    
	public boolean containsPoint(double x, double y) 
	{
		return position.Sub(new Vec2(x,y)).Mag2() <= radius * radius;
	}
	public void setArea(double area)
    {
    	this.area=area;
    	radius = Math.sqrt(area/Math.PI);
		speed = baseSpeed*speedBuffer/(speedBuffer+radius-minBlobRadius);

    }
    public double getRadius()
    {
    	return radius;
    }
	public double getArea() 
	{
		return area;
	}    
	public boolean isProcessed() 
	{
		return processed;
	}
	public void setProcessed(boolean processed) 
	{
		this.processed = processed;
	}

	public Vec2 getPosition() {
		return position;
	}

	public void setPosition(Vec2 position) {
		this.position = position;
	}

	public AI getAI() {
		return ai;
	}

	public void setAi(AI ai) {
		this.ai = ai;
	}
	
	public double getSpeed() {
		return speed;
	}

	public double getGrowthRate() 
	{
		return growthRate;
	}

	public double getStrength() {
		return strength;
	}

	public void move(Vec2 moveVector)
	{
		position = TorusMath.instance.move(position, moveVector);
	}

	public void movePreference(double timeStep) 
	{
		if (preferenceVector.Mag() > I_CARE)
		{
			Vec2 moveVector = preferenceVector.Unit().Scale(getSpeed()*timeStep);
			move(moveVector);
		}
	}

	public void setPreferenceVector(Vec2 preferenceVector) 
	{
		this.preferenceVector = preferenceVector;
	}

}
